﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Assignment3.Entities
{
    internal class ReflectThingy : Entity
    {
        public Model Model;
        private GraphicsDevice _device;
        private EnvironmentMapEffect _environmentMapEffect;
        private Effect customEffect;
        private RenderTargetCube _renderTargetCube;
        public Matrix ViewMatrix;
        public Matrix ProjectionMatrix;
        private float _nearPlane = 0.01f, _farPlane = 1000f;

        #region bump
        Texture2D diffuseTexture;
        Texture2D normalTexture;

        // The object that will contain our shader
        Effect effect;

        // Parameters for our shader object
        EffectParameter projectionParameter;
        EffectParameter viewParameter;
        EffectParameter worldParameter;
        EffectParameter ambientIntensityParameter;
        EffectParameter ambientColorParameter;

        // new parameters for diffuse light
        EffectParameter diffuseIntensityParameter;
        EffectParameter diffuseColorParameter;
        EffectParameter lightDirectionParameter;

        EffectParameter eyePosParameter;
        EffectParameter specularColorParameter;

        EffectParameter colorMapTextureParameter;
        EffectParameter normalMapTextureParameter;

        // Misc
        Matrix world, view, projection;
        float ambientLightIntensity;
        Vector4 ambientLightColor;
        Vector3 eyePos;
        #endregion

        public ReflectThingy(Camera camera, GraphicsDevice device, Effect fx)
            : base(camera)
        {
            _device = device;
            _renderTargetCube = new RenderTargetCube(_device, 512, false, SurfaceFormat.Color, DepthFormat.Depth16);
            ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, 4f/3f, _nearPlane, _farPlane);
            _environmentMapEffect = new EnvironmentMapEffect(_device);
            effect = fx;
            InitShader();
        }

        public void CreateCubeMap(CubeMapFace cubeMapFace)
        {
            _environmentMapEffect.GraphicsDevice.SetRenderTarget(_renderTargetCube, cubeMapFace);

            switch (cubeMapFace)
            {
                    // Up
                case CubeMapFace.NegativeX:
                    ViewMatrix = Matrix.CreateLookAt(
                        Vector3.Zero,
                        Vector3.Up, 
                        Vector3.Forward);
                    break;
                    // towards truck
                case CubeMapFace.PositiveX:
                    ViewMatrix = Matrix.CreateLookAt(
                        Vector3.Zero,
                        Vector3.Left,
                        Vector3.Up);
                    break;
                    // Towards backtruck
                case CubeMapFace.NegativeY:
                    ViewMatrix = Matrix.CreateLookAt(
                        Vector3.Zero,
                        Vector3.Forward,
                        Vector3.Up);
                    break;
                    //bottom
                case CubeMapFace.PositiveY:
                    ViewMatrix = Matrix.CreateLookAt(
                        Vector3.Zero,
                        Vector3.Down,
                        Vector3.Backward);
                    break;
                    //towards car
                case CubeMapFace.NegativeZ:
                    ViewMatrix = Matrix.CreateLookAt(
                        Vector3.Zero,
                        Vector3.Right,
                        Vector3.Up);
                    break;
                    // away from everything
                case CubeMapFace.PositiveZ:
                    ViewMatrix = Matrix.CreateLookAt(
                        Vector3.Zero,
                        Vector3.Backward,
                        Vector3.Up);
                    break;
            }
        }

        public void EndCubeMap()
        {
            _environmentMapEffect.GraphicsDevice.SetRenderTarget(null);
        }

        public void InitShader()
        {
            // Bind the parameters with the shader.
            worldParameter = effect.Parameters["World"];
            viewParameter = effect.Parameters["View"];
            projectionParameter = effect.Parameters["Projection"];

            ambientColorParameter = effect.Parameters["AmbientColor"];
            ambientIntensityParameter = effect.Parameters["AmbientIntensity"];

            diffuseColorParameter = effect.Parameters["DiffuseColor"];
            diffuseIntensityParameter = effect.Parameters["DiffuseIntensity"];
            lightDirectionParameter = effect.Parameters["LightDirection"];

            eyePosParameter = effect.Parameters["EyePosition"];
            specularColorParameter = effect.Parameters["SpecularColor"];

            colorMapTextureParameter = effect.Parameters["ColorMap"];
            normalMapTextureParameter = effect.Parameters["NormalMap"];

            ambientLightIntensity = 0.3f;
            ambientLightColor = Color.White.ToVector4();
        }

        public override void Draw()
        {
            projectionParameter.SetValue(Camera.Projection);
            viewParameter.SetValue(Camera.View);
            worldParameter.SetValue(Matrix.Identity);
            ambientIntensityParameter.SetValue(ambientLightIntensity);
            ambientColorParameter.SetValue(ambientLightColor);
            diffuseColorParameter.SetValue(Color.White.ToVector4());
            diffuseIntensityParameter.SetValue(0.3f);
            specularColorParameter.SetValue(Color.White.ToVector4());
            eyePosParameter.SetValue(Camera.Position);
            colorMapTextureParameter.SetValue(Texture);
            normalMapTextureParameter.SetValue(Texture);

            Vector3 lightDirection = new Vector3(0, 1, -1);

            //ensure the light direction is normalized, or
            //the shader will give some weird results
            lightDirection.Normalize();
            lightDirectionParameter.SetValue(lightDirection);

            effect.CurrentTechnique = effect.Techniques["Technique1"];

            foreach (ModelMesh mesh in Model.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    part.Effect = _environmentMapEffect;
                    _environmentMapEffect.EnvironmentMap = _renderTargetCube;
                    _environmentMapEffect.EnvironmentMapAmount = 6;
                    _environmentMapEffect.View = Camera.View;
                    _environmentMapEffect.Projection = Camera.Projection;
                    _environmentMapEffect.World = ObjectWorld;
                    _environmentMapEffect.CurrentTechnique.Passes[0].Apply();
                }
                mesh.Draw();
            }

            foreach (ModelMesh mesh in Model.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    for (int i = 0; i < effect.CurrentTechnique.Passes.Count; i++)
                    {
                        part.Effect = effect;
                        effect.CurrentTechnique.Passes[i].Apply();
                    }
                }
                mesh.Draw();
            }

            
        }
    }
}

